#ifndef NODELINKEDLIST_H_
#define NODELINKEDLIST_H_

#include "Node.h"

class NodeLinkedList {

private:
	class ListNode {

		public:
			Node& m_graphNodeData; // reference to graph-node data
			ListNode* m_prevListNode; // pointer to previous node on list
			ListNode* m_nextListNode; // pointer to next node on list

			/***************************************************************************************
			 * function name: Node (Node& nodeData)
			 * The Input: Graph node data to be set as list node's data attribute
			 * The output: None
			 * The Function operation: Creates a new node on list pointing to given graph node
			 ***************************************************************************************/
			ListNode(Node& nodeData);

			/***************************************************************************************
			 * function name: Node(const ListNode& listNodeToCopy)
			 * The Input: List node to be copied
			 * The output: None
			 * The Function operation: Creates a new list node identical to given list node
			 ***************************************************************************************/
			ListNode(const ListNode& listNodeToCopy);

			/****************************************************************************************
			 * function name: ~ListNode()
			 * The Input: None
			 * The output: None
			 * The Function operation: Destructs list node object
			 ***************************************************************************************/
			~ListNode();
	};

	ListNode* m_headDummy; // pointer to first node on list
	ListNode* m_tailDummy; // pointer to last node on list
	ListNode* m_currNode; // pointer to current node on list, user can change the node it is pointing at and get a pointer to current data // TODO DEBUG!!!

	/***************************************************************************************
	 * function name: findPlace(const Node& newGraphNode)
	 * The Input: Reference to graph node to add
	 * The output: List node pointer to which the new graph node should be linked.
	 * 			   If a graph node with new graph node's number already exists, NULL is returned
	 * The Function operation: The method checks if a graph node with the new graph node's number
	 * 						   already exists. If no such graph node was found, the method
	 * 						   returns a list node pointer which before it new graph node
	 * 						   will be linked
	 ***************************************************************************************/
	ListNode* findPlace(const Node& newGraphNode) const;

	/***************************************************************************************
	 * function name: internalAdd(Node& newGraphNode, ListNode* before)
	 * The Input: Reference to graph node to be added and a pointer to the list node where the
	 * 			  new graph node will be linked
	 * The output: None
	 * The Function operation: The method creates a new list node pointing to the new graph
	 * 					       node and links the new graph node in the given location to the
	 * 					       list
	 ***************************************************************************************/
	void internalAdd(Node& newGraphNode, ListNode* before);


public:
	/***************************************************************************************
	 * function name: NodeLinkedList()
	 * The Input: None
	 * The output: None
	 * The Function operation: Creates a new graph node linked list
	 ***************************************************************************************/
	NodeLinkedList();

	/***************************************************************************************
	 * function name: NodeLinkedList(const NodeLinkedList& listToCopy)
	 * The Input: List to be copied
	 * The output: None
	 * The Function operation: Creates a new list identical to given list
	 ***************************************************************************************/
	NodeLinkedList(const NodeLinkedList& listToCopy);

	/***************************************************************************************
	 * function name: ~NodeLinkedList()
	 * The Input: None
	 * The output: None
	 * The Function operation: Deletes the graph node linked list but not the pointed data
	 ***************************************************************************************/
	~NodeLinkedList();

	/***************************************************************************************
	 * function name: addNode(const Node* newGraphNode)
	 * The Input: Pointer to graph node to be added
	 * The output: True if graph node was added, False is not
	 * The Function operation: If there is already a graph node with the new graph node's
	 * 				           number graph is not added.
	 * 						   Otherwise, it adds the graph node and keeps the list sorted
	 * 						   from lowest number value to highest. New graph
	 *			               node is not changed
	 ***************************************************************************************/
	bool addNode(const Node& newGraphNode);

	/***************************************************************************************
	 * function name: removeListNode(const Nodeh& nodeDataToRmv)
	 * The Input: Reference to graph node data whose list node should be removed
	 * The output: True if removal was successful, False if not
	 * The Function operation: Search for list node that hold given data. If one was found,
	 * 						   it is removed
	 ***************************************************************************************/
	bool removeListNode(const Node& nodeDataToRmv);

	/***************************************************************************************
	 * function name: operator << (ostream &os, const NodeLinkedList& listToPrint)
	 * The Input: Reference to node liked list to be printed
	 * The output: ostream reference
	 * The Function operation: TODO
	 ***************************************************************************************/
	friend ostream& operator << (ostream &os, const NodeLinkedList& listToPrint);

	/***************************************************************************************
	 * function name: initializeCurrNode()
	 * The Input: None
	 * The output: None
	 * The Function operation: Sets current node pointer to point at list's head dummy node
	 ***************************************************************************************/
	void initializeCurrNode() {m_currNode = m_headDummy;}

	/***************************************************************************************
	 * function name: incrmntCurrNode()
	 * The Input: None
	 * The output: False if reached list's tail dummy node or if a next list node does
	 * 			   not exist. Otherwise, returns true
	 * The Function operation: Sets current node pointer to point at list's head dummy node
	 ***************************************************************************************/
	bool incrmntCurrNode();

	/***************************************************************************************
	 * function name: getCurrNode()
	 * The Input: None
	 * The output: Reference to graph node data of list node being pointed by current node pointer
	 * The Function operation: Returns graph node data attribute of list node being pointed by
	 * 						   current node pointer. Method does not change the object
	 ***************************************************************************************/
	const Node& getCurrGraphNode() const {return m_currNode->m_graphNodeData;}


	/***************************************************************************************
	 * function name: searchByKey(const Node& key)
	 * The Input: Node (in graph) to look for
	 * The output: Pointer to graph node that's equal to given key. If no such graph
	 * 			   node exists, NULL is returned.
	 * The Function operation: Scans list- if a match is found, a pointer to this graph node
	 * 						   is returned. If not, NULL is returned.
	 * 						   Method does not change list object
	 ***************************************************************************************/
	const Node* searchByKey(const Node& key) const;

	/***************************************************************************************
	 * function name: searchByKey(const int& key)
	 * The Input: Number to look for a graph node holding it
	 * The output: Pointer to graph node that's equal to given key. If no such graph
	 * 			   node exists, NULL is returned.
	 * The Function operation: Scans list- if a match is found, a pointer to this graph node
	 * 						   is returned. If not, NULL is returned.
	 * 						   Method does not change list object
	 ***************************************************************************************/
	const Node* searchByKey(const int& key) const;

	/***************************************************************************************
	 * function name: incrementNodesValue()
	 * The Input: None
	 * The output: None
	 * The Function operation: Increments node's (in graph) values
	 ***************************************************************************************/
	void incrementNodesValue();

	/***************************************************************************************
	 * function name: decrementNodesValue()
	 * The Input: None
	 * The output: None
	 * The Function operation: Decrements node's (in graph) values
	 ***************************************************************************************/
	void decrementNodesValue();

	/***************************************************************************************
	 * function name: operator == (const NodeLinkedList& listOperand)
	 * The Input: Graph node linked list to compare with
	 * The output: True if all nodes are equal, False if not
	 * The Function operation: Compares each list's nodes. Method does not change the object
	 ***************************************************************************************/
	bool operator == (const NodeLinkedList& listOperand) const;
};

#endif
